package com.access.boot.autoconfigure.apisdk;

import com.access.boot.apisdk.annotation.RequestMapping;
import com.access.boot.autoconfigure.apisdk.proxy.AccessorProxyBean;
import org.springframework.beans.factory.annotation.AnnotatedBeanDefinition;
import org.springframework.beans.factory.config.BeanDefinitionHolder;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.beans.factory.support.GenericBeanDefinition;
import org.springframework.context.annotation.ClassPathBeanDefinitionScanner;
import org.springframework.core.type.AnnotationMetadata;

import java.util.Set;

/**
 * @author Yangzhen
 * @date 2022/5/28 15:03
 * @since 1.0.0
 */
public class ClassPathAccessorScanner extends ClassPathBeanDefinitionScanner {

    public ClassPathAccessorScanner(BeanDefinitionRegistry registry) {
        super(registry, false);
    }

    @Override
    protected Set<BeanDefinitionHolder> doScan(String... basePackages) {
        Set<BeanDefinitionHolder> beanDefinitionHolders = super.doScan(basePackages);
        GenericBeanDefinition definition;
        for (BeanDefinitionHolder beanDefinitionHolder : beanDefinitionHolders) {
            definition = (GenericBeanDefinition) beanDefinitionHolder.getBeanDefinition();
            // bean的名称
            String beanClassName = definition.getBeanClassName();
            // 设置 AccessorProxyBean，实现了 FactoryBean
            definition.setBeanClass(AccessorProxyBean.class);
            // 原始接口作为构造器的参数传入
            definition.getConstructorArgumentValues().addGenericArgumentValue(beanClassName);
        }
        return beanDefinitionHolders;
    }

    public void registerFilters() {
        addIncludeFilter((metadataReader, metadataReaderFactory) -> true);
        addExcludeFilter(
                (metadataReader, metadataReaderFactory) -> {
                    String className = metadataReader.getClassMetadata().getClassName();
                    return className.endsWith("package-info");
                }
        );
    }

    @Override
    protected boolean isCandidateComponent(AnnotatedBeanDefinition beanDefinition) {
        AnnotationMetadata metadata = beanDefinition.getMetadata();
        return metadata.isInterface()
                & (metadata.hasAnnotatedMethods(RequestMapping.class.getName()));
    }

}
